package com.vhall.component.service.data.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.data.AccountForDataMapper;
import com.vhall.component.dao.room.RoomMapper;
import com.vhall.component.dao.room.RoomReservationThirdMapper;
import com.vhall.component.entity.data.dto.ViewingRecordsDTO;
import com.vhall.component.entity.data.vo.SelectedVideoReqVO;
import com.vhall.component.entity.data.vo.SelectedVideoRspVO;
import com.vhall.component.entity.data.vo.UserBasicStatisticsRspVO;
import com.vhall.component.entity.data.vo.UserParamVO;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.room.entity.AnchorRoomRelationEntity;
import com.vhall.component.entity.room.entity.RoomReservationThirdEntity;
import com.vhall.component.entity.room.entity.RoomsEntity;
import com.vhall.component.entity.room.enums.LiveContentTypeEnum;
import com.vhall.component.entity.room.enums.RoomAuditStatusEnum;
import com.vhall.component.entity.room.enums.RoomStatusEnum;
import com.vhall.component.entity.subject.enums.StatusEnum;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.service.data.PersonalCenterService;
import com.vhall.component.service.room.impl.RoomBaseService;
import com.vhall.component.service.room.utils.RoomUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Preconditions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.vhall.component.plugin.common.constant.RedisKey.*;

/**
 * PersonalCenterServiceImpl-
 *
 * @author xing.wang
 * @date 2023/10/17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PersonalCenterServiceImpl extends RoomBaseService implements PersonalCenterService {

    @Resource
    private RoomReservationThirdMapper roomReservationThirdMapper;

    @Autowired
    private RoomMapper roomMapper;

    @Value("${guoxin.column.default_name:''}")
    private String defaultName;

    @Autowired
    private AccountForDataMapper accountForDataMapper;

    /**
     * 过期时间单位是秒
     */
    private final Integer timeout = 3;

    @Override
    public PageVO<SelectedVideoRspVO> liveBooking(SelectedVideoReqVO reqVO) {
        Token token = TokenThreadLocal.getToken();
        String phone = token.getPhone();
        Preconditions.checkArgument(StringUtils.isNotBlank(phone), "当前人员手机号为空");

        int currPage = reqVO.getPage();
        // 每页显示的数据条数
        int pageSize = reqVO.getPageSize();

        String key = MessageFormat.format("{0}:{1}:{2}:{3}", CACHE_LIVE_BOOKING, currPage, pageSize, phone);
        String key2 = MessageFormat.format("{0}:{1}:{2}:{3}", CACHE_LIVE_BOOKING_COUNT, currPage, pageSize, phone);

        Object o = redisTemplate.opsForValue().get(key);
        Object o2 = redisTemplate.opsForValue().get(key2);

        int total = 0;
        List<SelectedVideoRspVO> rooms = new ArrayList<>();
        if (o != null && o2 != null) {
            rooms = JSON.parseArray(o.toString(), SelectedVideoRspVO.class);
            total = Integer.parseInt(o2.toString());
        } else {
            // 获取当然人员订阅记录
            LambdaQueryWrapper<RoomReservationThirdEntity> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(RoomReservationThirdEntity::getPhone, phone);
            queryWrapper.eq(RoomReservationThirdEntity::getStatus, StatusEnum.OPEN.getValue());
            List<RoomReservationThirdEntity> roomReservationThirdEntities = roomReservationThirdMapper.selectList(queryWrapper);


            if (CollectionUtil.isNotEmpty(roomReservationThirdEntities)) {

                LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
                wrapper.in(RoomsEntity::getIlId, roomReservationThirdEntities.stream().map(RoomReservationThirdEntity::getIlId).collect(Collectors.toList()));
                wrapper.eq(RoomsEntity::getAuditStatus, RoomAuditStatusEnum.APPROVED.getAuditStatus());
                wrapper.eq(RoomsEntity::getLiveInlet, 0);
                List<RoomsEntity> roomsEntityList = roomMapper.selectList(wrapper);

                if (CollectionUtil.isNotEmpty(roomsEntityList)) {
                    total = roomsEntityList.size();


                    // 获取栏目信息
                    Map<Integer, String> columnMap = getColumnStringMap(roomsEntityList);
                    // 获取主播名称
                    Map<Integer, AnchorRoomRelationEntity> userNameMap = getUserName(roomsEntityList);

                    Map<Integer, Long> virtualPV =  roomInnerService.getVirtualPV(roomsEntityList.stream().map(RoomsEntity::getIlId).collect(Collectors.toList()));
                    for (RoomsEntity record : roomsEntityList) {
                        rooms.add(convertToRoomsEntityVO(record, columnMap, userNameMap, virtualPV));
                    }

                    // 排序
                    rooms = sortList(rooms, reqVO);

                    redisTemplate.opsForValue().set(key, JSON.toJSONString(rooms), timeout, TimeUnit.SECONDS);
                    redisTemplate.opsForValue().set(key2, total, timeout, TimeUnit.SECONDS);
                }
            }
        }


        return new PageVO<>(reqVO.getPage(), reqVO.getPageSize(), total, rooms);
    }

    /**
     * 数据类型转换
     *
     * @param room
     * @param columnMap
     * @param userNameMap
     * @param virtualPV
     * @return
     */
    private SelectedVideoRspVO convertToRoomsEntityVO(RoomsEntity room
            , Map<Integer, String> columnMap
            , Map<Integer, AnchorRoomRelationEntity> userNameMap
            , Map<Integer, Long> virtualPV) {
        SelectedVideoRspVO vo = new SelectedVideoRspVO();
        // 拷贝实体
        BeanUtils.copyProperties(room, vo);
        vo.setName(room.getSubject());
        vo.setImage(room.getCoverImage());
        //查询 直播时长
        vo.setLiveTime(findLiveTime(room));

        //获取直播对外显示的直播状态
        Integer showRoomStatus = roomInnerService.getShowRoomStatus(room);
        String statusStr = RoomUtils.getRoomStatusStr(room.getAuditStatus(), showRoomStatus, roomAuditWitch);
        vo.setStatus(showRoomStatus);
        vo.setStatusStr(statusStr);

        int pvCount = getPvCountFromStatics(room);
        int pv = !virtualPV.isEmpty() && virtualPV.get(room.getIlId()) != null ? Math.toIntExact(virtualPV.get(room.getIlId())) + pvCount : pvCount;

        Integer totalNumberOfViews = Optional.ofNullable(room.getTotalNumberOfViews()).orElse(0);
        pv += totalNumberOfViews;
        vo.setPv(pv);

        vo.setColumnName(columnMap.isEmpty() || room.getColumnId() == null || room.getColumnId() == 0 ? defaultName : columnMap.get(room.getColumnId()));
        vo.setUserName(userNameMap.isEmpty() || userNameMap.get(room.getIlId()) == null ? "" : userNameMap.get(room.getIlId()).getUserName());
        vo.setOrgName(userNameMap.isEmpty() || userNameMap.get(room.getIlId()) == null ? "" : userNameMap.get(room.getIlId()).getOrgName());
        vo.setOrgCode(userNameMap.isEmpty() || userNameMap.get(room.getIlId()) == null ? "" : userNameMap.get(room.getIlId()).getOrgCode());
        vo.setLiveContentTypeName(LiveContentTypeEnum.getDescription(vo.getLiveContentType()));
        return vo;
    }

    private int getPvCountFromStatics(RoomsEntity room) {
        UserParamVO reqVO = new UserParamVO();
        reqVO.setIlId(room.getIlId());

        String key = MessageFormat.format("{0}:{1}", CACHE_SELECTEDVIDEOLIST_GETPVCOUNTFROMSTATICS, JSON.toJSONString(reqVO));
        Object o = redisTemplate.opsForValue().get(key);
        if (o != null) {
            return Integer.parseInt(o.toString());
        }

        UserBasicStatisticsRspVO ubsrv = accountForDataMapper.getBasicStatisticsInfo(reqVO);
        int pvCount = (ubsrv.getPvCount() != null && ubsrv.getPvCount() > 0) ? ubsrv.getPvCount() : 0;

        UserBasicStatisticsRspVO ubsrvVod = accountForDataMapper.getVodBasicStatisticsInfo(reqVO);
        pvCount += (ubsrvVod.getPvCount() != null && ubsrvVod.getPvCount() > 0) ? ubsrvVod.getPvCount() : 0;

        redisTemplate.opsForValue().set(key, pvCount, timeout, TimeUnit.SECONDS);
        return pvCount;
    }

    /**
     * 排序
     * 1、按照直播中、预告、结束-直播结束无回放、回放-直播结束有回放 的顺序展示，默认展示10条数据，上滑时加载更多；
     * 2、按照预计开始时间倒叙顺序展示；
     *
     * @param rooms
     * @return
     */
    private List<SelectedVideoRspVO> sortList(List<SelectedVideoRspVO> rooms, SelectedVideoReqVO reqVO) {
        ArrayList<SelectedVideoRspVO> result = new ArrayList<>();

        Map<Integer, List<SelectedVideoRspVO>> listMap = rooms.stream().collect(Collectors.groupingBy(SelectedVideoRspVO::getStatus));

        List<SelectedVideoRspVO> videoRspVOS = listMap.get(RoomStatusEnum.LIVE_BROADCAST.getStatus());
        if (CollectionUtils.isNotEmpty(videoRspVOS)) {
            List<SelectedVideoRspVO> collect = videoRspVOS.stream().sorted(Comparator.comparing(SelectedVideoRspVO::getStartTime))
                    .collect(Collectors.toList());
            result.addAll(collect);
        }

        List<SelectedVideoRspVO> videoRspVOS2 = listMap.get(RoomStatusEnum.TO_BE_BROADCAST.getStatus());
        if (CollectionUtils.isNotEmpty(videoRspVOS2)) {
            if (CollectionUtils.isNotEmpty(videoRspVOS2)) {
                List<SelectedVideoRspVO> collect = videoRspVOS2.stream().sorted(Comparator.comparing(SelectedVideoRspVO::getStartTime))
                        .collect(Collectors.toList());
                result.addAll(collect);
            }
        }

        // 结束-直播结束无回放
        List<SelectedVideoRspVO> rspVOS = rooms.stream().filter(e -> e.getStatus().equals(RoomStatusEnum.END_BROADCAST.getStatus())
                && StringUtils.isBlank(e.getRecordId())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(rspVOS)) {
            List<SelectedVideoRspVO> collect1 = rspVOS.stream().sorted(Comparator.comparing(SelectedVideoRspVO::getStartTime)).collect(Collectors.toList());
            result.addAll(collect1);
        }

        // 结束-直播结束有回放
        List<SelectedVideoRspVO> rspVOS2 = rooms.stream().filter(e -> e.getStatus().equals(RoomStatusEnum.END_BROADCAST.getStatus())
                && StringUtils.isNotBlank(e.getRecordId())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(rspVOS2)) {
            List<SelectedVideoRspVO> collect1 = rspVOS2.stream().sorted(Comparator.comparing(SelectedVideoRspVO::getStartTime)).collect(Collectors.toList());
            result.addAll(collect1);
        }


        // 手动的做分页
        int currPage = reqVO.getPage();
        // 每页显示的数据条数
        int pageSize = reqVO.getPageSize();

//            printLog(result, pageSize);


        // 手动进行分页
        int fromIndex = (currPage - 1) * pageSize;
        int toIndex = Math.min(currPage * pageSize, result.size());
        if (fromIndex > toIndex) {
            result = new ArrayList<>();
        } else {
            List<SelectedVideoRspVO> selectedVideoRspVOS = result.subList(fromIndex, toIndex);
            result = new ArrayList<>(selectedVideoRspVOS);
        }


        return result;
    }

    @Override
    public PageVO<ViewingRecordsDTO> viewingRecords(SelectedVideoReqVO reqVO) {

        Token token = TokenThreadLocal.getToken();
        Integer accountId = token.getAccountId();

        int currPage = reqVO.getPage();
        // 每页显示的数据条数
        int pageSize = reqVO.getPageSize();

        String key = MessageFormat.format("{0}:{1}:{2}:{3}", CACHE_VIEWING_RECORDS, currPage, pageSize, accountId);
        String key2 = MessageFormat.format("{0}:{1}:{2}:{3}", CACHE_VIEWING_RECORDS_COUNT, currPage, pageSize, accountId);

        Object o = redisTemplate.opsForValue().get(key);
        Object o2 = redisTemplate.opsForValue().get(key2);

        int total = 0;
        List<ViewingRecordsDTO> rooms = new ArrayList<>();
        if (o != null && o2 != null) {
            rooms = JSON.parseArray(o.toString(), ViewingRecordsDTO.class);
            total = Integer.parseInt(o2.toString());
        } else {
            // 获取当前人员直播的观看记录
            Page<ViewingRecordsDTO> page = new Page<>(currPage, pageSize);
            IPage<ViewingRecordsDTO> viewingRecords = accountForDataMapper.viewingRecordsNew(page, accountId);

            if (CollectionUtil.isNotEmpty(viewingRecords.getRecords())) {

                total = new BigDecimal(viewingRecords.getTotal()).intValue();
                rooms = viewingRecords.getRecords();

                LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
                wrapper.in(RoomsEntity::getIlId, rooms.stream().map(ViewingRecordsDTO::getIlId).collect(Collectors.toList()));
                wrapper.eq(RoomsEntity::getAuditStatus, RoomAuditStatusEnum.APPROVED.getAuditStatus());
                wrapper.eq(RoomsEntity::getLiveInlet, 0);
                List<RoomsEntity> roomsEntityList = roomMapper.selectList(wrapper);

                if (CollectionUtil.isNotEmpty(roomsEntityList)) {

                    // 获取栏目信息
                    Map<Integer, String> columnMap = getColumnStringMap(roomsEntityList);
                    // 获取主播名称
                    Map<Integer, AnchorRoomRelationEntity> userNameMap = getUserName(roomsEntityList);

                    Map<Integer, Long> virtualPV = roomInnerService.getVirtualPV(viewingRecords.getRecords().stream().map(ViewingRecordsDTO::getIlId).collect(Collectors.toList()));

                    Map<Integer, ViewingRecordsDTO> viewingRecordsDTOMap = rooms.stream().collect(Collectors.toMap(SelectedVideoRspVO::getIlId, e -> e));

                    for (RoomsEntity roomsEntity : roomsEntityList) {
                        SelectedVideoRspVO selectedVideoRspVO = convertToRoomsEntityVO(roomsEntity, columnMap, userNameMap, virtualPV);
                        ViewingRecordsDTO dto = viewingRecordsDTOMap.get(roomsEntity.getIlId());
                        BeanCopyUtil.copy(selectedVideoRspVO, dto);
                    }

                    redisTemplate.opsForValue().set(key, JSON.toJSONString(rooms), timeout, TimeUnit.SECONDS);
                    redisTemplate.opsForValue().set(key2, total, timeout, TimeUnit.SECONDS);
                }
            }
        }


        return new PageVO<>(reqVO.getPage(), reqVO.getPageSize(), total, rooms);
    }
}
